package com.wosai.register.util;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ImageUtil {
    private static Log logger = LogFactory.getLog(ImageUtil.class);
    
    public static BufferedImage scale(BufferedImage src, double ratio)
    {
       if (ratio >= 1.0)
           return src;
       
       logger.info(String.format("src width %d, height %d", src.getWidth(), src.getHeight()));
       
       int width = (int)(src.getWidth() * ratio);
       int height = (int)(src.getHeight() * ratio);
       
       Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
       BufferedImage out = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
       Graphics g = out.getGraphics();
       g.drawImage(image, 0, 0, null);
       g.dispose();
       
       return out;
    }
    
    public static double bound(int width, int height, int maxWidth, int maxHeight)
    {
        double horizontalRatio = (double)maxWidth / width;
        double verticalRatio = (double)maxHeight / height;
        return Math.min(horizontalRatio, verticalRatio);
    }
    
    public static void scale(InputStream is, OutputStream os, int maxWidth, int maxHeight) throws IOException
    {
        BufferedImage src = ImageIO.read(is);
        double ratio = bound(src.getWidth(), src.getHeight(), maxWidth, maxHeight);
        BufferedImage out = scale(src, ratio);
        ImageIO.write(out, "JPEG", os);
    }

    public static void scale(InputStream is, OutputStream os, double ratio) throws IOException
    {
        BufferedImage src = ImageIO.read(is);
        BufferedImage out = scale(src, ratio);
        ImageIO.write(out, "JPEG", os);
    }

    public static byte[] image2Bytes(BufferedImage out, String format) throws IOException
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(out, format, baos);
        return baos.toByteArray();
    }

    public static Triple<byte[], byte[], String> scale(InputStream is, int maxWidth, int maxHeight, int thWidth, int thHeight) throws IOException
    {
        Pair<BufferedImage, String> result = readAndGetFormat(is);
        
        BufferedImage src = result.getFirst();
        String format = result.getSecond();
        
        double ratio = bound(src.getWidth(), src.getHeight(), maxWidth, maxHeight);
        BufferedImage out = scale(src, ratio);
        byte[] data = image2Bytes(out, format);
        
        double ratio2 = bound(src.getWidth(), src.getHeight(), thWidth, thHeight);
        out = scale(src, ratio2);
        
        byte[] thumb = image2Bytes(out, format);
        return new Triple<byte[], byte[], String>(data, thumb, format);
    }

    public static byte[] scale(InputStream is, int maxWidth, int maxHeight) throws IOException
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        scale(is, baos, maxWidth, maxHeight);
        return baos.toByteArray();
    }

    public static byte[] scale(InputStream is, double ratio) throws IOException
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        scale(is, baos, ratio);
        return baos.toByteArray();
    }
    
    public static void main(String[] args) throws Exception
    {
        if (args.length!=1)
        {
            System.err.println("usage: ImageUtil filename");
            return;
        }
        
        String filename = args[0];
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filename));
        
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filename+".out.jpg"));
        
        scale(bis, bos, 0.2);
        bos.close();
        
    }
    
    public static Pair<BufferedImage, String> readAndGetFormat(InputStream is) {
        try {
            ImageInputStream iis = ImageIO.createImageInputStream(is);
            Iterator<ImageReader> iter = ImageIO.getImageReaders(iis);
            if (!iter.hasNext()) {
                return null;
            }
            ImageReader reader = (ImageReader) iter.next();

            
            ImageReadParam param = reader.getDefaultReadParam();
            reader.setInput(iis, true, true);
            BufferedImage bi;
            try {
                bi = reader.read(0, param);
            } finally {
                reader.dispose();
                iis.close();
            }
            String format = reader.getFormatName();
            
            return new Pair<BufferedImage, String>(bi, format);

        } catch (IOException e) {
            logger.warn(ExceptionUtils.getStackTrace(e));
        }
        return null;
    }
    
}
